﻿/// <Summary> 
/// $Author: Nikhil Chinchwade 
/// This file provides classes to export the monitoring data to csv files

/// $Creation Date : 
/// </summary>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MindTree.PerfWorkbench.Azure.Monitor.Core;
using System.IO;

namespace MindTree.PerfWorkbench.Azure.Monitor.AzureMonLib.result
{
    /// <summary>
    /// Resultobserver implementation to extract the relevant data and store it in CSV format
    /// </summary>
    public class CSVExport : PerfMonResultObserver
    {
        public static CSVExport ExportCSV = new CSVExport();
               
        /// <summary>
        /// Constructor: subscribes to the resultdatasource
        /// </summary>
        public CSVExport()
        {
            PerfResultDataSource.Instance.Subscribe(this);
        }

        public static void ExportNow()
        {
            //ExportCSV.UpdateData();
        }

        /// <summary>
        /// Publish the current monitoring data to CSV file
        /// </summary>
        public override void UpdateData()
        {          
            if (AzureMonInstanceContext.IsExportChecked)
            {
                StringBuilder Data = new StringBuilder();

                PerfDataRowComparer resultrowcomparer = new PerfDataRowComparer();
                IEnumerable<PerfDataRow> DistinctCounters = PerfResultDataSource.Instance.MonData.Distinct<PerfDataRow>(resultrowcomparer);

                IDictionary<string, RoleInstanceResultData> RoleResults = GetDistinctRoleInstance(DistinctCounters);

                foreach (PerfDataRow row in PerfResultDataSource.Instance.MonData)
                {
                    RoleResults[row.RoleInstance].AddValue(row);
                }

                foreach (RoleInstanceResultData r in RoleResults.Values)
                {
                    r.WriteToFile();
                }
            }                        
        }

        /// <summary>
        /// Create header info to be written to a CSV file
        /// </summary>
        /// <param name="paramDistinctCounters">List of distinct counters being monitored</param>
        /// <returns>Header String</returns>
        public string GetHeader(IEnumerable<PerfDataRow> paramDistinctCounters)
        {
            StringBuilder header = new StringBuilder();
            foreach (PerfDataRow row in paramDistinctCounters)
            {
                header.Append("\\\\");
                header.Append(row.RoleInstance);
                header.Append(row.CounterName);
                header.Append(",");
            }
            if (header.Length > 0)
            {
                return header.Remove(header.ToString().Count() - 1, 1).ToString();
            }
            return "";
        }

        /// <summary>
        /// Get distinct azure roles being monitored based on the counters list
        /// </summary>
        /// <param name="paramDistinctCounters">List of distinct counters being monitored</param>
        /// <returns>Dictionary of Azure role and their montioring resutls in a dictionary</returns>
        public Dictionary<string,RoleInstanceResultData> GetDistinctRoleInstance(IEnumerable<PerfDataRow> paramDistinctCounters)
        {
            Dictionary<string, RoleInstanceResultData> RoleInstances = new Dictionary<string, RoleInstanceResultData>();
            foreach (PerfDataRow row in paramDistinctCounters)
            {
                if (!RoleInstances.Keys.Contains(row.RoleInstance))
                {
                    RoleInstanceResultData r = new RoleInstanceResultData(row.RoleInstance);
                    r.DistinctCntrs.Add(row.CounterName);
                    RoleInstances.Add(row.RoleInstance, r);
                }
                else
                {
                    RoleInstances[row.RoleInstance].DistinctCntrs.Add(row.CounterName);
                }
            }
            return RoleInstances;
        }
    }



    /// <summary>
    /// Create CSV formatted data in data structure to be written to file
    /// </summary>
    public class RoleInstanceResultData
    {
        bool HeaderParsed = false;

        bool IsTimeSame = true;

        public string RoleInstance;

        public List<TimeValue> DataRowValues = new List<TimeValue>();

        public StringBuilder DataInstance = new StringBuilder();

        public List<string> DistinctCntrs = new List<string>();

        public RoleInstanceResultData(string paramRoleInstance)
        {
            RoleInstance = paramRoleInstance;
        }

        /// <summary>
        /// Add a monitoring result row to the current monitoring CSV result object
        /// </summary>
        /// <param name="row"></param>
        public void AddValue(PerfDataRow row)
        {
            if (!HeaderParsed)
            {
                DataInstance.Append("TimeStamp(GMT),");
                
                foreach (string r in DistinctCntrs)
                {
                    DataInstance.Append("\\\\" + RoleInstance + r + ",");
                }
                DataInstance.AppendLine("");
                HeaderParsed = true;
            }

            int index = DistinctCntrs.IndexOf(row.CounterName);

            foreach (TimeValue val in DataRowValues)
            {
                if (val.time != row.EventTickCount)
                {
                    IsTimeSame = false;
                    break;
                }
            }
            if( IsTimeSame )
            {
                try
                {
                    DataRowValues.Insert(index, new TimeValue(row.EventTickCount, row.CounterValue.ToString()));
                }
                catch (Exception ex)
                {
                }
            }
            //DataRowValues[index] = row.CounterValue.ToString();
            if (index == DistinctCntrs.Count() - 1)
            {
                DataInstance.Append(new DateTime(row.EventTickCount) + ",");
                foreach(TimeValue timevalue in DataRowValues)
                {
                    DataInstance.Append(timevalue.value);
                    DataInstance.Append(",");
                }
                DataInstance.AppendLine("");
                DataRowValues.Clear();
            }

        }

        /// <summary>
        /// Write the monitoring CSV result object to the configured file
        /// </summary>
        public void WriteToFile()
        {
            if (!File.Exists(AzureMonInstanceContext.ExportFileLocation + RoleInstance))
            {
                FileStream stream = File.Create(AzureMonInstanceContext.ExportFileLocation + RoleInstance);
                stream.Close();
            }

            File.AppendAllText(AzureMonInstanceContext.ExportFileLocation + RoleInstance, DataInstance.ToString());
        }        
    }

    /// <summary>
    /// Class to represent time
    /// </summary>
    public class TimeValue
    {
        public long time;

        public string value;

        public TimeValue(long paramTime, string paramValue)
        {
            time = paramTime;
            value = paramValue;        
        }
    }


    /// <summary>
    /// Equality comparer class for Azure performance counters
    /// </summary>
    public class PerfDataRowComparer : IEqualityComparer<PerfDataRow>
    {    
        /// <summary>
        /// Equality comparer for performance counters
        /// </summary>
        /// <param name="x">Performance counter from Result row object</param>
        /// <param name="y">Performance counter from Result row object</param>
        /// <returns>Boolean</returns>
        public bool Equals(PerfDataRow x, PerfDataRow y)
        {
            if (x.RoleInstance.Equals(y.RoleInstance) && x.CounterName.Equals(y.CounterName))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// GetHashCode
        /// </summary>
        /// <param name="obj">Performance counter from Result row object</param>
        /// <returns>Integer</returns>
        public int GetHashCode(PerfDataRow obj)
        {
            return base.GetHashCode();
        }
    }
}
